#pragma once

#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <functional>


#include "Log.hpp"
#include "Common.hpp"
#include "InetAddr.hpp"
#include "Thread.hpp"
#include "Threadpool.hpp"

static const uint16_t gport = 8081;
#define BACKLOG 8

using namespace LogModule;
using namespace ThreadPoolMudule;

using handler_t = std::function<std::string(std::string)>; // 期望：传递字符串，返回基于该命令的

class TcpServer
{
	using task_t = std::function<void()>;
public:
	TcpServer(handler_t handler,int port = gport)
		: _port(port)
		, _handler(handler)
	{
	}
	void InitServer()
	{
		// 1.创建tcp sockfd
		// int socket(int domain, int type, int protocol);

		_listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); // SOCK_STREAM：提供有序、可靠、双向、基于连接的字节流
		if (_listensockfd < 0)
		{
			LOG(LogLevel::FATAL) << "socket error";
			Die(SOCKET_ERR);
		}
		LOG(LogLevel::INFO) << "socket create sucess,sockfd is: " << _listensockfd;

		// 1.1 填充socket信息

		struct sockaddr_in local;
		memset(&local, 0, sizeof(local));
		local.sin_family = AF_INET;
		local.sin_port = ::htons(gport);
		local.sin_addr.s_addr = INADDR_ANY; // 绑定任意ip地址

		// 2.bind
		// int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

		int n = ::bind(_listensockfd, CONV(&local), sizeof(local));
		if (n < 0)
		{
			LOG(LogLevel::FATAL) << "bind error";
			Die(BIND_ERR);
		}
		LOG(LogLevel::INFO) << "bind sucess,sockfd is: " << _listensockfd;

		// 3. tcp是面向连接的，就要求tcp随时随地等待被连接
		// int listen(int sockfd, int backlog);  backlog：指定了等待连接队列的最大长度

		n = ::listen(_listensockfd, BACKLOG);
		if (n < 0)
		{
			LOG(LogLevel::FATAL) << "listen error";
			Die(LISTEN_ERR);
		}
		LOG(LogLevel::INFO) << "listen sucess,sockfd is: " << _listensockfd;
	}

	void HandlerRequest(int sockfd) // tcp也是全双工，一个文件描述符可以读可以写
	{
		LOG(LogLevel::INFO) << "HandlerRequest,sockfd is: " << sockfd;
		char inbuffer[4096];
		while (1)
		{
			//ssize_t n = ::read(sockfd, inbuffer, sizeof(inbuffer) - 1); // read读取时不完善的
			ssize_t n = ::recv(sockfd, inbuffer, sizeof(inbuffer) - 1,0); 
			if (n > 0)
			{
				inbuffer[n] = 0;
				LOG(LogLevel::INFO) << inbuffer;

				std::string cmd_result = _handler(inbuffer);

				//::write(sockfd, echo_str.c_str(), echo_str.size()); write写入也是不完善的
				::send(sockfd, cmd_result.c_str(), cmd_result.size(),0);
			}
			else if (n == 0) // read 如果读取返回值是0，表示client退出
			{
				LOG(LogLevel::INFO) << "client quit" << sockfd;
				break;
			}
			else // 读取失败了
				break;
		}
		::close(sockfd); // fd泄漏问题
	}

	void Start()
	{
		_isrunning = true;
		while (_isrunning)
		{
			// 不能直接读取数据

			// 1.获取新连接
			// int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

			struct sockaddr_in peer;
			socklen_t peerlen = sizeof(peer);
			LOG(LogLevel::DEBUG) << "accept ing...";

			// 获取client的信息：数据从sockfd获取，client的网络地址socket信息从accept获取||udp是recvfrom
			int sockfd = ::accept(_listensockfd, CONV(&peer), &peerlen);
			if (sockfd < 0)
			{
				LOG(LogLevel::WARNING) << "accept error" << strerror(errno);
				continue;
			}

			// 2.获取连接成功
			LOG(LogLevel::INFO) << "accept sucess,sockfd is" << sockfd;
			InetAddr addr(peer);
			LOG(LogLevel::INFO) << "client info: " << addr.Addr();

			// 线程池版本： 比较适合处理短任务，或者用户量少的情况

			// 构建任务
			//task_t f = std::bind(&TcpServer::HandlerRequest,this,sockfd);
			//ThreadPool<task_t>::getInstance()->Equeue(f);

			ThreadPool<task_t>::getInstance()->Equeue([this,sockfd](){   // lambda是临时对象，临时对象具有右值性质
				this->HandlerRequest(sockfd);
			});
		}
	}
	~TcpServer()
	{
	}

private:
	int _listensockfd; // 监听socket
	uint16_t _port;
	bool _isrunning;

	handler_t _handler;
};